
#include <BPainter>
#include "member_BHBoxLayout.h"
#include "member_BVBoxLayout.h"
#include "member_BDockLayout.h"

using namespace BWE;

member_BDockLayout::member_BDockLayout(BDockLayout* layout)
{
	boss = layout;
	sizeStretch.setStretch(99999.0f, 99999.0f);
	spacing = 0;
	pressed = false;
	handleIndex = -1;
}
member_BDockLayout::~member_BDockLayout()
{

}

void member_BDockLayout::fresHandleRect(const BPoint& pos)
{
	resizePart = Part_None;
	handleIndex = -1;
	const BSize& size = boss->size();
	for (int i = 0; i < items.size(); i++)
	{
		LayoutItem& item = items(i);
		if (!item.finishWidth && !item.finishHeight && sizeStretch.widthStretch() > 0.0f && sizeStretch.heightStretch() > 0.0f)
		{
			BRect rectLeftTop(item.rect.left() - spacing, item.rect.top() - spacing, spacing + spacing, spacing + spacing);
			if (!(item.align & Align_Left) && !(item.align & Align_Top) && rectLeftTop.contain(pos))
			{
				resizePart = Part_LeftTop;
				handleIndex = i;
				return;
			}
			BRect rectLeftBottom(item.rect.left() - spacing, item.rect.bottom() - spacing, spacing + spacing, spacing + spacing);
			if (!(item.align & Align_Left) && !(item.align & Align_Bottom) && rectLeftBottom.contain(pos))
			{
				resizePart = Part_LeftBottom;
				handleIndex = i;
				return;
			}
			BRect rectRightTop(item.rect.right() - spacing, item.rect.top() - spacing, spacing + spacing, spacing + spacing);
			if (!(item.align & Align_Right) && !(item.align & Align_Top) && rectRightTop.contain(pos))
			{
				resizePart = Part_RightTop;
				handleIndex = i;
				return;
			}
			BRect rectRightBottom(item.rect.right() - spacing, item.rect.bottom() - spacing, spacing + spacing, spacing + spacing);
			if (!(item.align & Align_Right) && !(item.align & Align_Bottom) && rectRightBottom.contain(pos))
			{
				resizePart = Part_RightBottom;
				handleIndex = i;
				return;
			}
		}
		if (!item.finishWidth && sizeStretch.widthStretch() > 0.0f)
		{
			BRect rectLeft(item.rect.left() - spacing, item.rect.top(), spacing, item.rect.height());
			if (!(item.align & Align_Left) && rectLeft.contain(pos))
			{
				resizePart = Part_Left;
				handleIndex = i;
				return;
			}
			BRect rectRight(item.rect.right(), item.rect.top(), spacing, item.rect.height());
			if (!(item.align & Align_Right) && rectRight.contain(pos))
			{
				resizePart = Part_Right;
				handleIndex = i;
				return;
			}
		}
		if (!item.finishHeight && sizeStretch.heightStretch() > 0.0f)
		{
			BRect rectTop(item.rect.left(), item.rect.top() - spacing, item.rect.width(), spacing);
			if (!(item.align & Align_Top) && rectTop.contain(pos))
			{
				resizePart = Part_Top;
				handleIndex = i;
				return;
			}
			BRect rectBottom(item.rect.left(), item.rect.bottom(), item.rect.width(), spacing);
			if (!(item.align & Align_Bottom) && rectBottom.contain(pos))
			{
				resizePart = Part_Bottom;
				handleIndex = i;
				return;
			}
		}
	}
}
BRect member_BDockLayout::handleRect(LayoutItem& item, Part part)
{
	if (part == Part_Left)
		return BRect(item.rect.left() - spacing, item.rect.top(), spacing, item.rect.height());
	if (part == Part_Right)
		return BRect(item.rect.right(), item.rect.top(), spacing, item.rect.height());
	if (part == Part_Top)
		return BRect(item.rect.left(), item.rect.top() - spacing, item.rect.width(), spacing);
	if (part == Part_Bottom)
		return BRect(item.rect.left(), item.rect.bottom(), item.rect.width(), spacing);

	if (part == Part_LeftTop)
		return BRect(item.rect.left() - spacing, item.rect.top() - spacing, spacing + spacing, spacing + spacing);
	if (part == Part_LeftBottom)
		return BRect(item.rect.left() - spacing, item.rect.bottom() - spacing, spacing + spacing, spacing + spacing);
	if (part == Part_RightTop)
		return BRect(item.rect.right() - spacing, item.rect.top() - spacing, spacing + spacing, spacing + spacing);
	if (part == Part_RightBottom)
		return BRect(item.rect.right() - spacing, item.rect.bottom() - spacing, spacing + spacing, spacing + spacing);

	return BRect();
}
bool member_BDockLayout::dragHandle(const BPoint& pos)
{
	BPoint change = pos - pressedPos;
	BRect rect = pressedRect;
	if (resizePart & Part_Left)
		rect.left() = rect.left() + change.x();
	if (resizePart & Part_Top)
		rect.top() = rect.top() + change.y();
	if (resizePart & Part_Right)
		rect.right() = rect.right() + change.x();
	if (resizePart & Part_Bottom)
		rect.bottom() = rect.bottom() + change.y();

	LayoutItem& item = items[handleIndex];
	if (rect.width() > item.sizeHint.width() && !(item.sizePolicy.widthPolicy() & Policy_Expanding))
		rect.setWidth(item.sizeHint.width());
	if (rect.width() < item.sizeHint.width() && !(item.sizePolicy.widthPolicy() & Policy_Shrinking))
		rect.setWidth(item.sizeHint.width());
	if (rect.width() > item.maxSize.width())
		rect.setWidth(item.maxSize.width());
	if (rect.width() < item.minSize.width())
		rect.setWidth(item.minSize.width());

	if (rect.height() > item.sizeHint.height() && !(item.sizePolicy.heightPolicy() & Policy_Expanding))
		rect.setHeight(item.sizeHint.height());
	if (rect.height() < item.sizeHint.height() && !(item.sizePolicy.heightPolicy() & Policy_Shrinking))
		rect.setHeight(item.sizeHint.height());
	if (rect.height() > item.maxSize.height())
		rect.setHeight(item.maxSize.height());
	if (rect.height() < item.minSize.height())
		rect.setHeight(item.minSize.height());

	item.realSize = rect.size();
	item.size = rect.size();
	const BMargin& margin = boss->margin();
	BRect crect = boss->rect();
	crect.left() += margin.left();
	crect.right() -= margin.right();
	crect.top() += margin.top();
	crect.bottom() -= margin.bottom();
	BRect itemRect = crect.align(item.align, item.realSize);
	item.adjust(itemRect);

	if (sizeStretch.widthStretch() > 0.0f)
	{
		float ratio = ((item.realSize.width() - item.sizeHint.width()) / (float)crect.width());
		item.stretch.widthStretch() = ratio * sizeStretch.widthStretch();
	}
	if (sizeStretch.heightStretch() > 0.0f)
	{
		float ratio = ((item.realSize.height() - item.sizeHint.height()) / (float)crect.height());
		item.stretch.heightStretch() = ratio * sizeStretch.heightStretch();
	}

	return true;
}

void member_BDockLayout::distributeSize()
{
	const BMargin& margin = boss->margin();
	BRect crect = boss->rect();
	crect.left() += margin.left();
	crect.right() -= margin.right();
	crect.top() += margin.top();
	crect.bottom() -= margin.bottom();
	for (int i = 0; i < items.size(); i++)
	{
		LayoutItem& item = items[i];
		if (item.dirty)
			item.flush();
		item.prepare(0, 0, 0);
	}
	if (sizeStretch.widthStretch() > 0.0f)
	{
		for (int i = 0; i < items.size(); i++)
		{
			LayoutItem& item = items[i];
			if (item.finishWidth)
				continue;
			if (item.stretch.widthStretch() == 0.0f)
				continue;
			int remainWidth = crect.width() - item.sizeHint.width();
			if (remainWidth > 0 && !(item.sizePolicy.widthPolicy() & Policy_Expanding))
			{
				continue;
			}
			if (remainWidth < 0 && !(item.sizePolicy.widthPolicy() & Policy_Shrinking))
			{
				continue;
			}
			int width = int(item.stretch.widthStretch() / sizeStretch.widthStretch() * remainWidth);
			if (width == 0)
				continue;
			int maxWidth = item.maxSize.width();
			if (width + item.realSize.width() > maxWidth)
			{
				item.realSize.width() = maxWidth;
				item.finishWidth = true;
				continue;
			}
			int minWidth = item.minSize.width();
			if (width + item.realSize.width() < minWidth)
			{
				item.realSize.width() = minWidth;
				item.finishWidth = true;
				continue;
			}
			item.realSize.width() += width;

		}
	}
	if (sizeStretch.heightStretch() > 0.0f)
	{
		for (int i = 0; i < items.size(); i++)
		{
			LayoutItem& item = items[i];
			if (item.finishHeight)
				continue;
			if (item.stretch.heightStretch() == 0.0f)
				continue;
			int remainHeight = crect.height() - item.sizeHint.height();
			if (remainHeight > 0 && !(item.sizePolicy.heightPolicy() & Policy_Expanding))
			{
				continue;
			}
			if (remainHeight < 0 && !(item.sizePolicy.heightPolicy() & Policy_Shrinking))
			{
				continue;
			}
			int height = int(item.stretch.heightStretch() / sizeStretch.heightStretch() * remainHeight);
			if (height == 0)
				continue;
			int maxHeight = item.maxSize.height();
			if (height + item.realSize.height() > maxHeight)
			{
				item.realSize.height() = maxHeight;
				item.finishHeight = true;
				continue;
			}
			int minHeight = item.minSize.height();
			if (height + item.realSize.height() < minHeight)
			{
				item.realSize.height() = minHeight;
				item.finishHeight = true;
				continue;
			}
			item.realSize.height() += height;
		}
	}
}
void member_BDockLayout::applyRects()
{
	const BMargin& margin = boss->margin();
	BRect crect = boss->rect();
	crect.left() += margin.left();
	crect.right() -= margin.right();
	crect.top() += margin.top();
	crect.bottom() -= margin.bottom();
	for (int i = 0; i < items.size(); i++)
	{
		LayoutItem& item = items[i];
		BRect itemRect = crect.align(item.align, item.realSize);
		item.adjust(itemRect);
	}
}
